package com.demo.auth.filter;

import com.alibaba.nacos.shaded.com.google.common.base.Joiner;
import com.demo.auth.bo.LoginUserBO;
import com.demo.common.base.pojo.JsonRes;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sudo.demo.security.exception.AuthException;
import com.sudo.demo.security.util.GsonUtil;
import com.sudo.demo.security.util.JwtUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 自定义JWT登录过滤器
 * 验证用户名密码正确后，生成一个token，并将token返回给客户端
 * 该类继承自UsernamePasswordAuthenticationFilter，重写了其中的2个方法
 * attemptAuthentication ：接收并解析用户凭证。
 * successfulAuthentication ：用户成功登录后，这个方法会被调用，我们在这个方法里生成token。
 */
public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;
    
    public JWTLoginFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    /**
     * 尝试身份认证(接收并解析用户凭证)
     * @param req 请求参数
     * @param res 返回参数
     * @return Authentication
     * @throws AuthenticationException 认证异常
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException {
        try {
            LoginUserBO user = new ObjectMapper().readValue(req.getInputStream(), LoginUserBO.class);
            return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>())
            );
        } catch (IOException e) {
            throw new AuthException("输入流读取异常");
        }
    }

    /**
     * 认证成功(用户成功登录后，这个方法会被调用，我们在这个方法里生成token)
     * @param request 请求参数
     * @param response 返回参数
     * @param chain 调用链
     * @param auth 认证信息
     * @throws IOException IO异常
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication auth) throws IOException {
        Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
        // 定义存放角色集合的对象
        List<String> authList = new ArrayList<>();
        for (GrantedAuthority grantedAuthority : authorities) {
            authList.add(grantedAuthority.getAuthority());
        }
        String authListStr = Joiner.on(",").join(authList);
        // username:authList 组合成jwt的subject
        String token = JwtUtil.createToken(auth.getPrincipal().toString()+":"+authListStr);

        // 登录成功后，返回token到body里面
        JwtUtil.JwtToken jwtToken = JwtUtil.createJwtToken(token);
        JsonRes<JwtUtil.JwtToken> jsonRes = JsonRes.ok(jwtToken);
        String json = GsonUtil.simpleObjToJson(jsonRes);
        response.getWriter().write(json);
    }

}